﻿using Microsoft.Xna.Framework;

using lumo.display.object2D;
using lumo.display.animation2D;
using lumo;
using System.Collections.Generic;
using System;

namespace game.display
{

    public class Camera : IPositionable2D, IUpdatable
    {
        private Vector2             _Position;
        private Vector2             _OffsetPosition = Vector2.Zero;
        private Vector2             _TargetPosition;
        private PositionAnimation2D _Animation;
        private const float         _Time = 250.0f;
        private Rectangle? _Boundaries = null;
        private Counter _ShakeCounter;
        private Counter _ShakeForceCounter;
        private List<Rectangle?> _BoundariesList = new List<Rectangle?>();

        public Vector2 Position
        {
            get { return _Position; }
            set { _Position = value; }
        }

        public Vector2 ScreenPosition
        {
            get { return _Position + _OffsetPosition; }
        }

        public float X
        {
            get { return _Position.X; }
            set { _Position.X = value; }
        }

        public float Y
        {
            get { return _Position.Y; }
            set { _Position.Y = value; }
        }

        public Camera()
        {
            _Position       = new Vector2(32.0f, 32.0f);
            _TargetPosition = new Vector2(32.0f, 32.0f);
            _Animation      = new PositionAnimation2D(_Position, _TargetPosition, 0, Smooth.Arrival, Loop.None, this);
        }

        public void SetTarget(Vector2 Target)
        {
            if (_Boundaries.HasValue)
            {
                _TargetPosition.X = MathHelper.Clamp(Target.X, _Boundaries.Value.Left, _Boundaries.Value.Right - Global.DefaultScreenSize.X);
                _TargetPosition.Y = MathHelper.Clamp(Target.Y, _Boundaries.Value.Top, _Boundaries.Value.Bottom - Global.DefaultScreenSize.Y);
            }
            else
            {
                _TargetPosition = Target;
            }
        }

        public void AddBoundaries(Rectangle? Boundaries)
        {
            _BoundariesList.Add(Boundaries);
            _Boundaries = _BoundariesList[_BoundariesList.Count-1];
            this.Position = _Position;
        }
        public void RemoveBoundaries(Rectangle? Boundaries)
        {
            _BoundariesList.Remove(Boundaries);
            _Boundaries = (_BoundariesList.Count > 0 ? _BoundariesList[_BoundariesList.Count - 1]  : null);
            this.Position = _Position;
        }

        public void SetBoundaries(Rectangle? Boundaries)
        {
            _Boundaries = Boundaries;
            this.Position = _Position;
        }

        public void Update(LumoComponent component)
        {
            if (_Position != _TargetPosition)
                _Animation = new PositionAnimation2D(_TargetPosition, _Time, Smooth.Arrival, Loop.None, this);
            _Animation.Update(component);
            if (_ShakeCounter != null)
            {
                _ShakeForceCounter.Update(component);
                _ShakeCounter.Update(component);
                _OffsetPosition = new Vector2((float)(Math.Sin(_ShakeCounter.Value) * _ShakeForceCounter.Value), 0.0f);
                if (_ShakeCounter.Finished)
                {
                    _OffsetPosition = Vector2.Zero;
                    _ShakeCounter = null;
                }
            }
        }

        public void Shake(float Force, float Time, int N = 1)
        {
            _ShakeCounter = new Counter(0, MathHelper.TwoPi * N, Time, Smooth.Arrival);
            _ShakeForceCounter = new Counter(Force, Force/2, Time, Smooth.Arrival);
        }

    }

}